import { defineComponent, ExtractPropTypes, PropType, provide } from 'vue'
import { FormContextKey, FormItemVm as FormItemExpose, FormRules } from './interface'

const formProps = {
  prefixCls: { default: 'x-form' },
  model: Object,
  layout: { type: String as PropType<'horizontal' | 'vertical'>, default: 'horizontal' },
  labelWidth: Number,
  rules: Object as PropType<FormRules>
}

export type FormProps = ExtractPropTypes<typeof formProps>

export default defineComponent({
  name: 'x-form',
  props: formProps,
  setup(props, { expose, slots }) {
    const formItems: Record<string, FormItemExpose> = {}

    function addItem(vm: FormItemExpose) {
      formItems[vm.props.prop] = vm
    }
    function delItem(vm: FormItemExpose) {
      delete formItems[vm.props.prop]
    }
    async function validate(): Promise<void> {
      await validateFields(Object.keys(formItems))
    }
    async function validateFields(fields: string[]): Promise<void> {
      const arr = fields.map(field => formItems[field].validate())
      await Promise.all(arr)
    }
    function clearValidate() {
      Object.values(formItems).forEach(item => item.clearValidate())
    }
    function resetFields() {
      Object.values(formItems).forEach(item => item.resetField())
    }

    expose({
      validate,
      validateFields,
      clearValidate,
      resetFields
    })

    provide(FormContextKey, {
      props,
      addItem,
      delItem
    })

    const onSubmit = (e: Event) => e.preventDefault()

    return () => {
      const { prefixCls, layout } = props

      const cls = [prefixCls, `${prefixCls}-${layout}`]

      return (
        <form class={cls} onSubmit={onSubmit}>
          {{ ...slots }}
        </form>
      )
    }
  }
})
